/**
 * Copyright (C) 2020 Baidu, Inc. All Rights Reserved.
 */
package com.baidu.mpks.backendweb.source.web;

import com.baidu.mpks.Authorized;
import com.baidu.mpks.backendweb.db.enums.SourceStatus;
import com.baidu.mpks.backendweb.file.service.FileRUDService;
import com.baidu.mpks.backendweb.ktree.service.TreeService;
import com.baidu.mpks.backendweb.source.dao.SourceManageDao;
import com.baidu.mpks.backendweb.source.domain.BatchSourceVO;
import com.baidu.mpks.backendweb.source.domain.DataSourceStatisticDayContentTypeVO;
import com.baidu.mpks.backendweb.source.domain.DataSourceStatisticDayInputTypeVO;
import com.baidu.mpks.backendweb.source.domain.DataSourceStatisticDayTrendVO;
import com.baidu.mpks.backendweb.source.domain.SourceVO;
import com.baidu.mpks.backendweb.source.domain.StructUpdateData;
import com.baidu.mpks.backendweb.source.dto.SourceResponse;
import com.baidu.mpks.backendweb.source.dto.StructUpdateVO;
import com.baidu.mpks.backendweb.source.service.SourceService;
import com.baidu.mpks.backendweb.source.service.SourceService.SearchCriteria;
import com.baidu.mpks.backendweb.source.service.SourceStatisticService;
import com.baidu.mpks.common.AbstractController;
import com.baidu.mpks.common.dto.CommonResponse;
import com.baidu.mpks.common.dto.ListDto;
import com.baidu.mpks.datasource.constant.SourceContentType;
import com.baidu.mpks.datasource.constant.SourceInputType;
import com.baidu.mpks.datasource.dao.SourceDao;
import com.baidu.mpks.datasource.domain.Source;
import com.baidu.mpks.datasource.domain.StructInfo;
import com.baidu.mpks.datasource.service.SourceMappingService;
import com.baidu.mpks.exception.BusinessException;
import com.baidu.mpks.user.domain.User;
import com.baidu.mpks.util.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.AbstractController;

import javax.validation.Valid;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author cuixuefei
 */
@RestController
@RequestMapping("/api/source")
@Slf4j
public class SourceController extends AbstractController {

    @Autowired
    SourceService sourceService;

    @Autowired
    SourceDao sourceDao;

    @Autowired
    SourceManageDao sourceManageDao;

    @Autowired
    SourceStatisticService sourceStatisticService;

    @Autowired
    FileRUDService fileRUDService;

    @Autowired
    TreeService treeService;

    @Autowired
    SourceMappingService sourceMappingService;

    @Value("${source.content.type}")
    String contentTypeStr;

    @PostMapping("/list")
    @Authorized(value = {"knowledge_resource"})
    public CommonResponse<ListDto<Source>> getList(@RequestBody SourceVO sourceVO) {
        if (sourceVO.getContentTypes().size() == 0) {
            throw new BusinessException("文件类型不能为空!");
        }

        if (sourceVO.getInputTypes().size() == 0) {
            throw new BusinessException("接入类型不能为空!");
        }

        ListDto<Source> data = sourceService.searchSource(sourceVO.getNodeId(), sourceVO.getInputTypes(),
                sourceVO.getContentTypes(), sourceVO.getPageSize(), sourceVO.getPageNumber());
        return createSuccessResponse(data);
    }

    @PostMapping("/add")
    @Authorized(value = {"knowledge_resource"})
    public CommonResponse addApi(@RequestBody @Valid Source source) {

        try {
            if (null == source.getNodeId()) {
                throw new BusinessException("知识树节点不能为空!");
            }
            Set<Integer> childrenNodes = treeService.getChildrensIncludeSelf(source.getNodeId());
            if (childrenNodes.size() > 1) {
                return createErrorResponse(-1, "请选择叶子节点上传");
            }
            sourceService.addSource(source);
        } catch (IOException e) {
            return createErrorResponse(CODE_SYSTEM_ERROR, e.getMessage());
        }
        return createEmptySuccessResponse();
    }

    @PostMapping("/update")
    @Authorized(value = {"knowledge_resource"})
    public CommonResponse updateApi(@RequestBody @Valid Source source) {

        try {
            sourceService.updateSource(source);
        } catch (IOException e) {
            return createErrorResponse(CODE_SYSTEM_ERROR, e.getMessage());
        }
        return createEmptySuccessResponse();
    }

    @PostMapping("/delete")
    @Authorized(value = {"knowledge_resource"})
    public CommonResponse deleteApi(@RequestBody @Valid Source source) {

        try {
            sourceService.deleteSource(source);
        } catch (IOException e) {
            return createErrorResponse(CODE_SYSTEM_ERROR, e.getMessage());
        }
        return createEmptySuccessResponse();
    }

    @PostMapping("/data/list")
    public CommonResponse getDataList(@RequestBody SearchCriteria sc) {
        Map<String, Object> data = new HashMap<>();
        if (sc.getContentType().equals(SourceContentType.FILE.getName())) {
            data = sourceService.getListFromMySql(sc, null);
        } else if (sc.getContentType().equals(SourceContentType.STRUCT.getName())) {
            data = sourceService.getStructList(sc);
        } else {
            data = sourceService.getListFromMongo(sc);
        }
        if (MapUtils.isEmpty(data)) {
            data.put("access", false);
        }
        return createSuccessResponse(data);
    }

    @PostMapping("/data/delete")
    @Authorized(value = {"knowledge_resource"})
    public CommonResponse getDataDelete(@RequestBody SourceVO sourceVO) {
        sourceService.deleteByFileIdsOrAtIds(sourceVO.getContentType(),
                sourceVO.getOriId() != null ? Arrays.asList(sourceVO.getOriId()) : null,
                sourceVO.getAtId() != null ? Arrays.asList(sourceVO.getAtId()) : null);
        return createEmptySuccessResponse();
    }

    @PostMapping("/data/batchDelete")
    @Authorized(value = {"knowledge_resource"})
    public CommonResponse dataBatchDelete(@RequestBody BatchSourceVO batchSourceVO) {

        sourceService.deleteByFileIdsOrAtIds(batchSourceVO.getContentType(), batchSourceVO.getOriIdList(),
                batchSourceVO.getAtIdList());
        return createEmptySuccessResponse();
    }

    @PostMapping("/data/structAdd")
    public CommonResponse addStruct(@RequestBody StructInfo structInfo) {
        sourceService.addStructData(structInfo);
        return createEmptySuccessResponse();
    }

    @PostMapping("/data/structUpdate")
    public CommonResponse updateStruct(@RequestBody StructUpdateVO structUpdateVO) {
        log.debug("structUpdate [StructUpdateVO{}]", structUpdateVO);
        // 回调判断数据是不是创建成功
        if (structUpdateVO.getCode().equals(0)) {
            // 回调更新结构化数据的总数信息
            sourceService.saveStructDataTotalAndStatus(structUpdateVO.getData(), structUpdateVO.getSourceId());
            log.info("updateStruct total success sourceId ------> {}", structUpdateVO.getSourceId());
        } else {
            sourceDao.updateStatusAndErrMsgById(structUpdateVO.getSourceId(), SourceStatus.CREATE_FAIL.getCode(),
                structUpdateVO.getMessage());
            log.info("updateStruct total fail sourceId ------> {}", structUpdateVO.getSourceId());
        }
        return createEmptySuccessResponse();
    }

    @PostMapping("/data/structSaveClass")
    public CommonResponse saveStructClass(@RequestBody StructUpdateData structUpdateData) {
        sourceService.saveClass(structUpdateData.getClassName(), structUpdateData.getAction(), null);
        return createEmptySuccessResponse();
    }

    /**
     * 获取已接入数据
     */
    @GetMapping("/satatistic/accessed")
    @Authorized(value = {"knowledge_statistics"})
    public CommonResponse<SourceResponse<DataSourceStatisticDayContentTypeVO>> queryAccessedData() {
        List<String> contentTypes = Stream.of(StringUtils.split(contentTypeStr, ","))
                .collect(Collectors.toList());
        List<DataSourceStatisticDayContentTypeVO> contentTypeData =
                sourceStatisticService.queryContentTypeData(contentTypes);
        int total = 0;
        for (DataSourceStatisticDayContentTypeVO dataSourceStatisticDayContentTypeVO : contentTypeData) {
            contentTypes.remove(dataSourceStatisticDayContentTypeVO.getContentType());
            total += dataSourceStatisticDayContentTypeVO.getTotal();
        }

        for (String contentType : contentTypes) {
            DataSourceStatisticDayContentTypeVO data = new DataSourceStatisticDayContentTypeVO();
            data.setContentType(contentType);
            data.setTotal(0);
            contentTypeData.add(data);
        }
        SourceResponse<DataSourceStatisticDayContentTypeVO> resp =
                new SourceResponse<DataSourceStatisticDayContentTypeVO>(total, DateUtil.getCurTime(), contentTypeData);

        return createSuccessResponse(resp);
    }

    /**
     * 获取数据分布情况
     */
    @GetMapping("/satatistic/distribution")
    @Authorized(value = {"knowledge_statistics"})
    public CommonResponse<SourceResponse<DataSourceStatisticDayInputTypeVO>> queryDistributionData() {
        List<DataSourceStatisticDayInputTypeVO> inputTypeData = sourceStatisticService.queryInputTypeData();
        int total = 0;

        List<String> inputTypeTotalZeroList = SourceInputType.getAllNames();

        List<String> inputTypeHasTotal = new ArrayList<>();

        for (DataSourceStatisticDayInputTypeVO dataSourceStatisticDayInputTypeVO : inputTypeData) {
            inputTypeHasTotal.add(dataSourceStatisticDayInputTypeVO.getInputType());
            total += dataSourceStatisticDayInputTypeVO.getTotal();
        }

        inputTypeTotalZeroList.removeAll(inputTypeHasTotal);

        inputTypeTotalZeroList.stream().forEach(item -> {
            DataSourceStatisticDayInputTypeVO data = new DataSourceStatisticDayInputTypeVO();
            data.setInputType(item);
            data.setTotal(0);
            inputTypeData.add(data);
        });
        SourceResponse<DataSourceStatisticDayInputTypeVO> resp =
                new SourceResponse<DataSourceStatisticDayInputTypeVO>(total, DateUtil.getCurTime(), inputTypeData);

        return createSuccessResponse(resp);
    }

    /**
     * 获取趋势数据
     */
    @GetMapping("/satatistic/trend")
    @Authorized(value = {"knowledge_statistics"})
    public CommonResponse queryTrendData(@RequestParam long beginDate, @RequestParam long endDate) {
        Map<String, List<DataSourceStatisticDayTrendVO>> mapResult = sourceStatisticService.queryDataTrend(beginDate,
                endDate);
        return createSuccessResponse(mapResult);
    }

    /**
     * 获取知识树节点已接入文件数
     */
    @PostMapping("/treenode/gettotal")
    public CommonResponse getNodeFilesTotal(@RequestBody Map<String, Object> map) {
        List<Map> treeNodeList = (List<Map>) map.get("treeNodeList");
        String contentType = (String) map.get("contentType");
        List<Map> treeNodeResultList = sourceStatisticService.queryNodeFilesTotal(treeNodeList, contentType);
        return createSuccessResponse(treeNodeResultList);
    }

    /**
     * 通过资源id获取节点信息
     */
    @GetMapping("/getInfoById")
    public CommonResponse<Source> getInfoById(@RequestParam int id) {
        Source data = sourceMappingService.getSource(id);
        return createSuccessResponse(data);
    }

    /**
     * 获取用户列表
     */
    @GetMapping(value = "/users")
    @Authorized(value = {"knowledge_resource"})
    public CommonResponse<List<User>> getUserList(@RequestParam(value = "contentType") String contentType) {
        return createSuccessResponse(sourceService.findUserList(contentType));
    }
}
